/*
 * $Id: PDFColorSpace.java,v 1.2 2007/12/20 18:33:34 rbair Exp $
 *
 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

package com.sun.pdfview.colorspace;

import java.awt.Color;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_ColorSpace;
import java.awt.color.ICC_Profile;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Map;

import com.sun.pdfview.PDFObject;
import com.sun.pdfview.PDFPaint;
import com.sun.pdfview.PDFParseException;
import com.sun.pdfview.function.PDFFunction;

/**
 * A color space that can convert a set of color components into
 * PDFPaint.
 * @author Mike Wessler
 */
public class PDFColorSpace {
    /** the name of the device-dependent gray color space */
    public static final int COLORSPACE_GRAY = 0;
    /** the name of the device-dependent RGB color space */
    public static final int COLORSPACE_RGB = 1;
    /** the name of the device-dependent CMYK color space */
    public static final int COLORSPACE_CMYK = 2;
    /** the name of the pattern color space */
    public static final int COLORSPACE_PATTERN = 3;
    
    /** the device-dependent color spaces */
    private static PDFColorSpace graySpace =
        new PDFColorSpace(ColorSpace.getInstance(ColorSpace.CS_GRAY));
    private static PDFColorSpace rgbSpace =
        new PDFColorSpace(ColorSpace.getInstance(ColorSpace.CS_sRGB));
    private static PDFColorSpace cmykSpace =
        new PDFColorSpace(new CMYKColorSpace());
    
    /** the pattern space */
    private static PDFColorSpace patternSpace = new PatternSpace();
    
    /** the color space */
    ColorSpace cs;

    /**
     * create a PDFColorSpace based on a Java ColorSpace
     * @param cs the Java ColorSpace
     */
    protected PDFColorSpace(ColorSpace cs) {
	this.cs= cs;
    }

    /**
     * Get a color space by name
     *
     * @param name the name of one of the device-dependent color spaces
     */
    public static PDFColorSpace getColorSpace(int name) {
        switch (name) {
            case COLORSPACE_GRAY:
                return graySpace;          
            case COLORSPACE_RGB:
                return rgbSpace;
            case COLORSPACE_CMYK:
                return cmykSpace; 
            case COLORSPACE_PATTERN:
                return patternSpace;
            default:
                throw new IllegalArgumentException("Unknown Color Space name: " + name);
        }
    }
    
    /**
     * Get a color space specified in a PDFObject
     *
     * @param csobj the PDFObject with the colorspace information
     */
    public static PDFColorSpace getColorSpace(PDFObject csobj, Map resources) 
        throws IOException 
    {  
        String name;
        
        PDFObject colorSpaces = null;
        if (resources != null) {
            colorSpaces = (PDFObject) resources.get("ColorSpace");
        }
        
        if (csobj.getType()== PDFObject.NAME) {
	    name = csobj.getStringValue();
	    if (name.equals("DeviceGray") || name.equals("G")) {
		return getColorSpace(COLORSPACE_GRAY);
	    } else if (name.equals("DeviceRGB") || name.equals("RGB")) {
		return getColorSpace(COLORSPACE_RGB);
	    } else if (name.equals("DeviceCMYK") || name.equals("CMYK")) {
		return getColorSpace(COLORSPACE_CMYK);
	    } else if (name.equals("Pattern")) {
		return getColorSpace(COLORSPACE_PATTERN);
	    } else if (colorSpaces != null) {
		csobj = (PDFObject) colorSpaces.getDictRef(name);
	    }
	}
        
        if (csobj == null) {
            return null;
        } else if (csobj.getCache() != null) {
	    return (PDFColorSpace) csobj.getCache();
	}
        
	PDFColorSpace value = null;
        
	// csobj is [/name <<dict>>]
	PDFObject[] ary = csobj.getArray();
        name = ary[0].getStringValue();

        if (name.equals("CalGray")) {
	    value = new PDFColorSpace(new CalGrayColor(ary[1]));
	} else if (name.equals("CalRGB")) {
	    value = new PDFColorSpace(new CalRGBColor(ary[1]));
	} else if (name.equals("Lab")) {
	    value = new PDFColorSpace(new LabColor(ary[1]));
	} else if (name.equals("ICCBased")) {
	    ByteArrayInputStream bais = new ByteArrayInputStream(ary[1].getStream());
	    ICC_Profile profile = ICC_Profile.getInstance(bais);
	    value = new PDFColorSpace(new ICC_ColorSpace(profile));
	} else if (name.equals("Separation") || name.equals("DeviceN")) {
            PDFColorSpace alternate = getColorSpace(ary[2], resources);
            PDFFunction function = PDFFunction.getFunction(ary[3]);
            
	    value = new AlternateColorSpace(alternate,  function);
	} else if (name.equals("Indexed") || name.equals("I")) {
	    PDFColorSpace refspace = getColorSpace(ary[1], resources);
            
	    // number of indices= ary[2], data is in ary[3];
	    int count = ary[2].getIntValue();
	    value = new IndexedColor(refspace, count, ary[3]);
	} else if (name.equals("Pattern")) {
            if (ary.length == 1) {
                return getColorSpace(COLORSPACE_PATTERN);
            }
            
            PDFColorSpace base = getColorSpace(ary[1], resources);
            return new PatternSpace(base);
        } else {
	    throw new PDFParseException("Unknown color space: " + name + " with " + ary[1]);
	}
        
	csobj.setCache(value);
	return value;
    }
    
    /**
     * get the number of components expected in the getPaint command
     */
    public int getNumComponents() {
	return cs.getNumComponents();
    }

    /**
     * get the PDFPaint representing the color described by the
     * given color components
     * @param components the color components corresponding to the given
     * colorspace
     * @return a PDFPaint object representing the closest Color to the
     * given components.
     */
    public PDFPaint getPaint(float[] components) {
	float rgb[]= cs.toRGB(components);
	return PDFPaint.getColorPaint(new Color(rgb[0], rgb[1], rgb[2]));
    }
    
    /**
     * get the original Java ColorSpace.
     */
    public ColorSpace getColorSpace() {
	return cs;
    }
}
